package com.zjun.core.param;

import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson2.JSON;
import com.zjun.core.UserContext;
import com.zjun.core.AbstractIdempotentExecuteHandler;
import com.zjun.core.IdempotentContext;
import com.zjun.core.IdempotentParamWrapper;
import com.zjun.exception.ClientException;
import jodd.util.StringUtil;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@RequiredArgsConstructor
public final class IdempotentParamExecuteHandler extends AbstractIdempotentExecuteHandler implements IdempotentParamService{

    private final RedissonClient redissonClient;

    private final static String LOCK = "lock:param:restAPI";

    @Override
    public void handler(IdempotentParamWrapper wrapper) {
        String lockKey = wrapper.getLocalKey();
        RLock lock = redissonClient.getLock(lockKey);
        if (!lock.tryLock()){
            throw new ClientException(wrapper.getIdempotent().message());
        }
        IdempotentContext.put(LOCK,lock);
    }


    @Override
    protected IdempotentParamWrapper buildWrapper(ProceedingJoinPoint joinPoint) {
        String localKey = String.format("idempotent:path:%s:currentUserId:%s:md5:%s",getSevletPath(),getCurrentUserId(),calcArgsMD5(joinPoint));
        return IdempotentParamWrapper.builder().localKey(localKey).joinPoint(joinPoint).build();
    }

    /**
     * 获取当前线程上下文
     * @return
     */
    private String getSevletPath(){
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        return requestAttributes.getRequest().getServletPath();
    }

    /**
     * 获取当前操作用户ID
     * @return
     */
    private String getCurrentUserId(){
        String userId = UserContext.getUserId();
        if (StringUtil.isBlank(userId)){
            throw new ClientException("用户ID获取失败，请登录");
        }
        return userId;
    }

    /**
     * @return joinPoint md5
     */
    private String calcArgsMD5(ProceedingJoinPoint joinPoint) {
        return DigestUtil.md5Hex(JSON.toJSONBytes(joinPoint.getArgs()));
    }


    @Override
    public void postProcessing() {super.postProcessing();}

}
